import os
import sys
import shutil
import threading
import time
from datetime import datetime
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox, Tk, Button, Label, Frame, StringVar, Checkbutton, BooleanVar, Radiobutton, Spinbox
from comtypes.client import CreateObject
import win32com.client
import pythoncom


class DocumentProcessor:
    def __init__(self):
        """
        初始化文档批量处理工具
        """
        self.source_folder = ""
        self.output_folder = ""
        self.is_processing = False
        self.processed_files = 0
        self.total_files = 0

        # 创建主窗口
        self.root = Tk()
        self.root.title("文档批量处理工具 v2.0")
        self.root.geometry("800x800")
        self.root.resizable(True, True)

        # 状态显示变量
        self.status_var = StringVar()
        self.status_var.set("准备就绪")

        # 选项变量
        self.process_excel_var = BooleanVar(value=True)
        self.copy_other_files_var = BooleanVar(value=True)

        # Excel设置变量
        self.page_orientation = StringVar(value="landscape")
        self.fit_to_page = BooleanVar(value=True)
        self.scale = tk.IntVar(value=100)
        self.center_horizontal = BooleanVar(value=True)
        self.center_vertical = BooleanVar(value=True)
        self.auto_fit_columns = BooleanVar(value=True)
        self.adjust_margins = BooleanVar(value=True)
        self.print_gridlines = BooleanVar(value=False)

        # 支持的文件类型
        self.word_extensions = ('.doc', '.docx')
        self.excel_extensions = ('.xls', '.xlsx')
        self.pdf_extensions = ('.pdf',)

        self.setup_ui()
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def setup_ui(self):
        """
        创建用户界面
        """
        # 标题
        title_frame = Frame(self.root, pady=20)
        title_frame.pack()
        Label(
            title_frame,
            text="文档批量处理工具",
            font=("Microsoft YaHei UI", 18, "bold")
        ).pack()

        # 说明
        instruction_frame = Frame(self.root)
        instruction_frame.pack(pady=10)
        instruction_text = """功能说明：
1. 自动扫描文件夹及其子文件夹
2. Word文件转换为PDF
3. Excel文件转换为PDF（完整设置选项）
4. 直接复制PDF文件和其他文件
5. 保持原文件夹层级结构"""

        Label(
            instruction_frame,
            text=instruction_text,
            font=("Microsoft YaHei UI", 10),
            justify="left"
        ).pack()

        # 创建主框架
        main_frame = Frame(self.root)
        main_frame.pack(fill="both", expand=True, padx=20, pady=10)

        # 左侧：选项设置
        left_frame = Frame(main_frame)
        left_frame.pack(side="left", fill="both", expand=True, padx=(0, 10))

        # 处理选项
        options_frame = Frame(left_frame)
        options_frame.pack(fill="x", pady=10)

        Label(options_frame, text="处理选项：", font=("Microsoft YaHei UI", 12, "bold")).pack(anchor="w")

        Checkbutton(
            options_frame,
            text="处理Excel文件（转换为PDF）",
            variable=self.process_excel_var,
            font=("Microsoft YaHei UI", 10)
        ).pack(anchor="w", padx=20)

        Checkbutton(
            options_frame,
            text="复制其他文件类型",
            variable=self.copy_other_files_var,
            font=("Microsoft YaHei UI", 10)
        ).pack(anchor="w", padx=20)

        # 右侧：Excel设置
        right_frame = Frame(main_frame)
        right_frame.pack(side="right", fill="both", expand=True, padx=(10, 0))

        # Excel转换设置
        excel_frame = Frame(right_frame)
        excel_frame.pack(fill="x", pady=10)

        Label(excel_frame, text="Excel转PDF设置：", font=("Microsoft YaHei UI", 12, "bold")).pack(anchor="w")

        # 页面方向设置
        orientation_frame = Frame(excel_frame)
        orientation_frame.pack(fill="x", padx=20, pady=5)
        Label(orientation_frame, text="页面方向:", font=("Microsoft YaHei UI", 10)).pack(anchor="w")
        Radiobutton(orientation_frame, text="横向", value="landscape",
                   variable=self.page_orientation, font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)
        Radiobutton(orientation_frame, text="纵向", value="portrait",
                   variable=self.page_orientation, font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)

        # 页面居中设置
        center_frame = Frame(excel_frame)
        center_frame.pack(fill="x", padx=20, pady=5)
        Label(center_frame, text="页面居中:", font=("Microsoft YaHei UI", 10)).pack(anchor="w")
        Checkbutton(center_frame, text="水平居中", variable=self.center_horizontal,
                   font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)
        Checkbutton(center_frame, text="垂直居中", variable=self.center_vertical,
                   font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)

        # 缩放设置
        scale_frame = Frame(excel_frame)
        scale_frame.pack(fill="x", padx=20, pady=5)
        Label(scale_frame, text="缩放选项:", font=("Microsoft YaHei UI", 10)).pack(anchor="w")
        Checkbutton(scale_frame, text="适应页面宽度", variable=self.fit_to_page,
                   font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)

        # 缩放比例
        scale_ratio_frame = Frame(scale_frame)
        scale_ratio_frame.pack(fill="x", padx=20, pady=5)
        Label(scale_ratio_frame, text="缩放比例:", font=("Microsoft YaHei UI", 9)).pack(side="left")
        scale_spin = Spinbox(scale_ratio_frame, from_=50, to=150, width=5, textvariable=self.scale,
                            font=("Microsoft YaHei UI", 9))
        scale_spin.pack(side="left", padx=5)
        Label(scale_ratio_frame, text="%", font=("Microsoft YaHei UI", 9)).pack(side="left")

        # 高级设置
        advanced_frame = Frame(excel_frame)
        advanced_frame.pack(fill="x", padx=20, pady=5)
        Label(advanced_frame, text="高级设置:", font=("Microsoft YaHei UI", 10)).pack(anchor="w")
        Checkbutton(advanced_frame, text="自动调整列宽（解决表头显示问题）", variable=self.auto_fit_columns,
                   font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)
        Checkbutton(advanced_frame, text="调整页面边距", variable=self.adjust_margins,
                   font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)
        Checkbutton(advanced_frame, text="显示网格线", variable=self.print_gridlines,
                   font=("Microsoft YaHei UI", 9)).pack(anchor="w", padx=20)

        # 按钮
        button_frame = Frame(left_frame)
        button_frame.pack(pady=20)

        button_style = {
            "width": 25,
            "height": 2,
            "font": ("Microsoft YaHei UI", 10),
            "bg": "#f0f0f0",
            "relief": "raised"
        }

        Button(
            button_frame,
            text="选择源文件夹",
            command=self.select_source_folder,
            **button_style
        ).pack(pady=10)

        Button(
            button_frame,
            text="选择输出文件夹",
            command=self.select_output_folder,
            **button_style
        ).pack(pady=10)

        Button(
            button_frame,
            text="开始处理",
            command=self.start_processing,
            **button_style
        ).pack(pady=10)

        # 状态显示
        status_frame = Frame(self.root)
        status_frame.pack(pady=20, fill="x", padx=20)
        Label(
            status_frame,
            textvariable=self.status_var,
            font=("Microsoft YaHei UI", 9),
            wraplength=550
        ).pack()

        # 页脚
        footer_frame = Frame(self.root)
        footer_frame.pack(side="bottom", pady=10)
        Label(
            footer_frame,
            text="© 2024 文档批量处理工具 V2.0",
            font=("Microsoft YaHei UI", 8)
        ).pack()

    def select_source_folder(self):
        """选择源文件夹"""
        if self.is_processing:
            messagebox.showwarning("警告", "正在处理中，请等待...")
            return

        folder = filedialog.askdirectory(title="选择源文件夹")
        if folder:
            self.source_folder = os.path.abspath(folder).replace('/', '\\')
            self.status_var.set(f"源文件夹: {self.source_folder}")

    def select_output_folder(self):
        """选择输出文件夹"""
        if self.is_processing:
            messagebox.showwarning("警告", "正在处理中，请等待...")
            return

        folder = filedialog.askdirectory(title="选择输出文件夹")
        if folder:
            self.output_folder = os.path.abspath(folder).replace('/', '\\')
            self.status_var.set(f"输出文件夹: {self.output_folder}")

    def scan_files(self, folder_path):
        """
        递归扫描文件夹，返回所有需要处理的文件
        """
        files_to_process = {
            'word': [],
            'excel': [],
            'pdf': [],
            'others': []
        }

        try:
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    file_path = os.path.join(root, file)
                    file_ext = os.path.splitext(file)[1].lower()

                    if file_ext in self.word_extensions:
                        files_to_process['word'].append(file_path)
                    elif file_ext in self.excel_extensions and self.process_excel_var.get():
                        files_to_process['excel'].append(file_path)
                    elif file_ext in self.pdf_extensions:
                        files_to_process['pdf'].append(file_path)
                    elif self.copy_other_files_var.get():
                        files_to_process['others'].append(file_path)

        except Exception as e:
            messagebox.showerror("错误", f"扫描文件夹时出错: {str(e)}")

        return files_to_process

    def convert_word_to_pdf(self, word_path, pdf_path, wps_app):
        """
        将Word文件转换为PDF（基于word转pdf.py的逻辑）
        """
        try:
            if not os.path.exists(word_path):
                return False, f"文件不存在: {word_path}"

            # 确保输出目录存在
            os.makedirs(os.path.dirname(pdf_path), exist_ok=True)

            # 打开文档
            doc = wps_app.Documents.Open(word_path)

            try:
                # 尝试不同的PDF导出方法
                doc.ExportAsFixedFormat(pdf_path, 17)
            except:
                try:
                    doc.SaveAs(pdf_path, 17)
                except:
                    doc.SaveAs2(pdf_path, FileFormat=17)

            doc.Close(SaveChanges=False)
            return True, pdf_path

        except Exception as e:
            return False, f"Word转换失败: {str(e)}"

    def convert_excel_to_pdf(self, excel_path, pdf_path, excel_app):
        """
        将Excel文件转换为PDF（基于excel转pdf.py的逻辑）
        """
        try:
            if not os.path.exists(excel_path):
                return False, f"文件不存在: {excel_path}"

            # 确保输出目录存在
            os.makedirs(os.path.dirname(pdf_path), exist_ok=True)

            # 打开工作簿
            wb = excel_app.Workbooks.Open(excel_path)

            # 处理每个工作表
            for ws in wb.Worksheets:
                # 页面设置
                ws.PageSetup.Orientation = 2 if self.page_orientation.get() == 'landscape' else 1
                ws.PageSetup.CenterHorizontally = self.center_horizontal.get()
                ws.PageSetup.CenterVertically = self.center_vertical.get()

                # 调整页面边距（解决表头显示问题）
                if self.adjust_margins.get():
                    ws.PageSetup.LeftMargin = excel_app.InchesToPoints(0.5)    # 左边距
                    ws.PageSetup.RightMargin = excel_app.InchesToPoints(0.5)   # 右边距
                    ws.PageSetup.TopMargin = excel_app.InchesToPoints(0.75)    # 上边距
                    ws.PageSetup.BottomMargin = excel_app.InchesToPoints(0.75) # 下边距
                    ws.PageSetup.HeaderMargin = excel_app.InchesToPoints(0.3)  # 页眉边距
                    ws.PageSetup.FooterMargin = excel_app.InchesToPoints(0.3)  # 页脚边距

                # 自动调整列宽（重要：解决表头显示不全的关键）
                if self.auto_fit_columns.get():
                    # 先选择所有使用的单元格
                    used_range = ws.UsedRange
                    if used_range:
                        # 自动调整列宽
                        used_range.Columns.AutoFit()

                        # 额外处理：确保每列至少有最小宽度
                        for col in range(1, used_range.Columns.Count + 1):
                            current_width = ws.Columns(col).ColumnWidth
                            # 如果列宽太小，设置最小宽度
                            if current_width < 8:  # 8是一个合理的最小宽度
                                ws.Columns(col).ColumnWidth = 8

                # 设置打印网格线
                ws.PageSetup.PrintGridlines = self.print_gridlines.get()

                # 设置缩放（在调整列宽之后）
                if self.fit_to_page.get():
                    ws.PageSetup.FitToPagesWide = 1
                    ws.PageSetup.FitToPagesTall = False
                    # 清除固定缩放设置
                    ws.PageSetup.Zoom = False
                else:
                    # 使用固定缩放
                    ws.PageSetup.Zoom = self.scale.get()
                    # 清除适应页面设置
                    ws.PageSetup.FitToPagesWide = False
                    ws.PageSetup.FitToPagesTall = False

                # 设置打印质量
                ws.PageSetup.PrintQuality = 300  # 设置为300DPI，提高清晰度

            # 导出PDF
            wb.ExportAsFixedFormat(0, pdf_path)
            time.sleep(0.5)
            wb.Close(SaveChanges=False)
            time.sleep(0.5)

            return True, pdf_path

        except Exception as e:
            return False, f"Excel转换失败: {str(e)}"

    def copy_file_with_structure(self, src_path, relative_path):
        """
        复制文件到输出目录，保持文件夹结构
        """
        try:
            dst_path = os.path.join(self.output_folder, relative_path)
            os.makedirs(os.path.dirname(dst_path), exist_ok=True)
            shutil.copy2(src_path, dst_path)
            return True, dst_path
        except Exception as e:
            return False, f"文件复制失败: {str(e)}"

    def get_relative_path(self, file_path):
        """
        获取文件相对于源文件夹的路径
        """
        return os.path.relpath(file_path, self.source_folder)

    def process_files(self):
        """
        主要的文件处理逻辑
        """
        success_count = 0
        error_files = []

        try:
            # 扫描文件
            files_to_process = self.scan_files(self.source_folder)

            # 计算总文件数
            self.total_files = (len(files_to_process['word']) +
                              len(files_to_process['excel']) +
                              len(files_to_process['pdf']) +
                              len(files_to_process['others']))

            # 初始化WPS应用程序
            wps_app = None
            excel_app = None

            if files_to_process['word']:
                pythoncom.CoInitialize()
                try:
                    wps_app = CreateObject('WPS.Application')
                except:
                    try:
                        wps_app = CreateObject('KWPS.Application')
                    except:
                        wps_app = CreateObject('ET.Application')
                wps_app.Visible = False
                wps_app.DisplayAlerts = False

            if files_to_process['excel']:
                try:
                    excel_app = win32com.client.Dispatch("KET.Application")
                    excel_app.Visible = False
                    excel_app.DisplayAlerts = False
                except:
                    error_files.append(("Excel应用", "无法初始化WPS表格，Excel文件将被跳过"))

            # 处理Word文件
            for word_path in files_to_process['word']:
                if not self.is_processing:
                    break

                self.processed_files += 1
                relative_path = self.get_relative_path(word_path)
                pdf_relative_path = os.path.splitext(relative_path)[0] + '.pdf'
                pdf_output_path = os.path.join(self.output_folder, pdf_relative_path)

                self.status_var.set(f"正在转换Word文件 ({self.processed_files}/{self.total_files}): {os.path.basename(word_path)}")
                self.root.update()

                success, result = self.convert_word_to_pdf(word_path, pdf_output_path, wps_app)
                if success:
                    success_count += 1
                else:
                    error_files.append((word_path, result))

            # 处理Excel文件
            if excel_app:
                for excel_path in files_to_process['excel']:
                    if not self.is_processing:
                        break

                    self.processed_files += 1
                    relative_path = self.get_relative_path(excel_path)
                    pdf_relative_path = os.path.splitext(relative_path)[0] + '.pdf'
                    pdf_output_path = os.path.join(self.output_folder, pdf_relative_path)

                    self.status_var.set(f"正在转换Excel文件 ({self.processed_files}/{self.total_files}): {os.path.basename(excel_path)}")
                    self.root.update()

                    success, result = self.convert_excel_to_pdf(excel_path, pdf_output_path, excel_app)
                    if success:
                        success_count += 1
                    else:
                        error_files.append((excel_path, result))

            # 复制PDF文件
            for pdf_path in files_to_process['pdf']:
                if not self.is_processing:
                    break

                self.processed_files += 1
                relative_path = self.get_relative_path(pdf_path)

                self.status_var.set(f"正在复制PDF文件 ({self.processed_files}/{self.total_files}): {os.path.basename(pdf_path)}")
                self.root.update()

                success, result = self.copy_file_with_structure(pdf_path, relative_path)
                if success:
                    success_count += 1
                else:
                    error_files.append((pdf_path, result))

            # 复制其他文件
            for other_path in files_to_process['others']:
                if not self.is_processing:
                    break

                self.processed_files += 1
                relative_path = self.get_relative_path(other_path)

                self.status_var.set(f"正在复制其他文件 ({self.processed_files}/{self.total_files}): {os.path.basename(other_path)}")
                self.root.update()

                success, result = self.copy_file_with_structure(other_path, relative_path)
                if success:
                    success_count += 1
                else:
                    error_files.append((other_path, result))

        except Exception as e:
            messagebox.showerror("错误", f"处理过程中发生错误: {str(e)}")

        finally:
            # 清理应用程序
            if wps_app:
                try:
                    wps_app.Quit()
                    del wps_app
                except:
                    pass
                pythoncom.CoUninitialize()

            if excel_app:
                try:
                    excel_app.Quit()
                except:
                    pass

        # 显示结果
        self.create_processing_report(success_count, error_files)
        self.is_processing = False
        self.status_var.set("处理完成")

    def create_processing_report(self, success_count, error_files):
        """
        创建处理报告
        """
        if success_count > 0:
            messagebox.showinfo(
                "完成",
                f"处理完成！\n成功: {success_count}\n失败: {len(error_files)}"
            )

        if error_files:
            log_path = os.path.join(self.output_folder, "处理错误日志.txt")
            try:
                with open(log_path, "w", encoding="utf-8") as f:
                    f.write(f"处理时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
                    for file_path, error in error_files:
                        f.write(f"文件: {file_path}\n")
                        f.write(f"错误: {error}\n\n")

                messagebox.showwarning(
                    "警告",
                    f"部分文件处理失败，详细信息已保存到：\n{log_path}"
                )
            except Exception as e:
                messagebox.showerror("错误", f"创建错误日志失败：{str(e)}")

    def start_processing(self):
        """
        开始处理
        """
        if self.is_processing:
            messagebox.showwarning("警告", "正在处理中...")
            return

        if not self.source_folder or not self.output_folder:
            messagebox.showerror("错误", "请先选择源文件夹和输出文件夹！")
            return

        if self.source_folder == self.output_folder:
            messagebox.showerror("错误", "源文件夹和输出文件夹不能相同！")
            return

        self.is_processing = True
        self.processed_files = 0
        self.total_files = 0

        threading.Thread(target=self.process_files, daemon=True).start()

    def on_closing(self):
        """
        窗口关闭时的处理
        """
        if self.is_processing:
            if messagebox.askyesno("警告", "处理正在进行中，确定要退出吗？"):
                self.is_processing = False
                time.sleep(0.5)
                self.root.destroy()
        else:
            self.root.destroy()

    def run(self):
        """
        运行应用程序
        """
        self.root.mainloop()


if __name__ == "__main__":
    app = DocumentProcessor()
    app.run()